package com.xbongbong.saas.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.ConfigConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormEntity;
import com.xbongbong.paas.elasticsearch.pojo.XbbAggregatedPage;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.model.PaasFormModel;
import com.xbongbong.paas.redis.PaasRedisHelper;
import com.xbongbong.paas.redis.RedisTimeConstant;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.JsonHelperUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.wrap.BaseVO;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.script.pojo.SyncUserToContactPojo;
import com.xbongbong.pro.script.pojo.dto.SyncUserToContactDTO;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.ext.ContactEntityExt;
import com.xbongbong.saas.domain.entity.ext.CustomerEntityExt;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ContactEnum;
import com.xbongbong.saas.enums.business.CustomerManagementEnum;
import com.xbongbong.saas.model.ContactModel;
import com.xbongbong.saas.model.IndexTypeModel;
import com.xbongbong.saas.service.SyncDataToXbbService;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.client.core.CountRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * @Author: hongxiao
 * @date: 2021-10-31 17:37
 */
@Service("syncDataToXbbService")
public class SyncDataToXbbServiceImpl implements SyncDataToXbbService {
    private static final Logger LOG = LoggerFactory.getLogger(SyncDataToXbbServiceImpl.class);

    /**
     * 最多同步10个联系人
     */
    private static final Integer MAX_ADD_CONTACT_COUNT = 10;
    /**
     * 同步到公司id
     */
    private static final String SYNC_CORPID_PRO = "dinge3fa697f86d461d2";
    /**
     * 同步公司对应的客户表单id
     */
    private static final Long SYNC_CUSTOMER_FORMID = 572924L;
    /**
     * 客户表单中代表被同步公司corpid的字段
     */
    private static final String CUSTOMER_FORM_CORPID = "text_28";
    /**
     * 同步公司对应的联系人表单id
     */
    private static final Long SYNC_CONTACT_FORMID = 572932L;

    @Resource
    private PaasRedisHelper paasRedisHelper;
    @Resource
    private XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;
    @Resource
    private ContactModel contactModel;
    @Resource
    private PaasFormModel paasFormModel;
    @Resource
    private IndexTypeModel indexTypeModel;

    @Override
    public BaseVO addContactRedis(SyncUserToContactDTO syncUserToContactDTO) throws XbbException {

        if (!BasicConstant.TASK_SECRET_KEY.equals(syncUserToContactDTO.getKey())) {
            LOG.error("key错误，停止缓存客户联系人数据！");
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100066, "key错误，停止缓存客户联系人数据！");
        }

        SyncUserToContactPojo syncUserToContactPojo = syncUserToContactDTO.getUser();
        if (syncUserToContactPojo == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100066, "无客户联系人数据！");
        }

        String corpid = syncUserToContactPojo.getCorpid();
        JSONObject userInfo;
        String userInfoStr = paasRedisHelper.getValue(ConfigConstant.SYNC_PRO_REDIS_PREFIX, ConfigConstant.ADD_CONTACT_TO_XBB);
        if (StringUtil.isNotEmpty(userInfoStr)) {
            userInfo = JsonHelperUtil.parseObject(userInfoStr);
        } else {
            userInfo = new JSONObject();
        }
        JSONArray userArray = new JSONArray();
        if (userInfo.containsKey(corpid)) {
            userArray = userInfo.getJSONArray(corpid);
        }
        boolean addFlag = true;
        if (CollectionsUtil.isNotEmpty(userArray)) {
            for (Object object : userArray) {
                SyncUserToContactPojo contactPojo = JsonHelperUtil.parseObject(object.toString(), SyncUserToContactPojo.class);
                if (Objects.equals(syncUserToContactPojo.getMobile(), contactPojo.getMobile())) {
                    addFlag = false;
                    break;
                }
            }
        }

        if (addFlag) {
            userArray.add(syncUserToContactPojo);
            userInfo.put(corpid, userArray);
            // 缓存数据一天
            paasRedisHelper.setValue(ConfigConstant.SYNC_PRO_REDIS_PREFIX, ConfigConstant.ADD_CONTACT_TO_XBB, userInfo.toJSONString(), RedisTimeConstant.LONG_DURATION);
        }

        return new BaseVO();
    }

    @Override
    public String syncContactToXbb(String key) {
        if (StringUtil.isEmpty(key)) {
            return " key 为 null";
        } else if (!BasicConstant.TASK_SECRET_KEY.equals(key)) {
            return " key 值错误！";
        }
        String syncStatus = paasRedisHelper.getValue(ConfigConstant.SYNC_PRO_REDIS_PREFIX, ConfigConstant.SYNC_CONTACT_STATUS_REDIS_KEY);
        if (StringUtil.isEmpty(syncStatus)) {
            paasRedisHelper.setValue(ConfigConstant.SYNC_PRO_REDIS_PREFIX, ConfigConstant.SYNC_CONTACT_STATUS_REDIS_KEY, "1", RedisTimeConstant.TEN_MINUTES);
        } else if ("1".equals(syncStatus)) {
            return "正在同步联系人信息";
        }
        //同步
        syncContact();
        // 清空状态缓存
        paasRedisHelper.removeValue(ConfigConstant.SYNC_PRO_REDIS_PREFIX, ConfigConstant.SYNC_CONTACT_STATUS_REDIS_KEY);

        return "操作成功";
    }

    /***
     * 同步联系人到销帮帮公司
     *
     * @return void
     * @author hongxiao
     * @date 2021-11-14 10:42
     * @since
     * @version
     */
    private void syncContact() {

        String userInfoStr = paasRedisHelper.getValue(ConfigConstant.SYNC_PRO_REDIS_PREFIX, ConfigConstant.ADD_CONTACT_TO_XBB);
        if (Objects.isNull(userInfoStr)) {
            LOG.info("同步联系人缓存不存在，无法同步！");
            return;
        }

        PaasFormEntity contactFormEntity = paasFormModel.getByKey(SYNC_CONTACT_FORMID, SYNC_CORPID_PRO);
        if (Objects.isNull(contactFormEntity)) {
            LOG.info("联系人表单模板不存在或已删除，无法同步");
            return;
        }

        JSONObject userInfoObj = JsonHelperUtil.parseObject(userInfoStr);
        Set<String> corpidSet = new HashSet<>(userInfoObj.keySet());

        // 获取客户数据
        List<CustomerEntityExt> customerList = getCustomerList(corpidSet);
        if (CollectionsUtil.isEmpty(customerList)) {
            LOG.info("同步联系人对应的客户不存在，无法同步");
            return;
        }
        IndexTypeEnum customerIndex = indexTypeModel.getCustomerIndex(SYNC_CORPID_PRO, XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), SaasMarkEnum.SAAS.getCode());

        // 需要删除的数据map
        Map<String, List<SyncUserToContactPojo>> deleteMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<SyncUserToContactPojo> deleteList = new ArrayList<>();

        for (CustomerEntityExt customerEntityExt : customerList) {

            JSONObject data = customerEntityExt.getData();
            Long customerId = customerEntityExt.getDataId();
            // 获取需要添加的联系人
            String customerCorpid = data.getString(CUSTOMER_FORM_CORPID);
            List<SyncUserToContactPojo> contactRedisList = userInfoObj.getJSONArray(customerCorpid).toJavaList(SyncUserToContactPojo.class);
            if (CollectionsUtil.isEmpty(contactRedisList)) {
                continue;
            }
            // 联系人缓存需要删除的数据
            deleteList.clear();

            for (SyncUserToContactPojo contactPojo : contactRedisList) {
                // 判断客户联系人是否超10个
                if (getContactCount(customerId) >= MAX_ADD_CONTACT_COUNT) {
                    deleteList.addAll(contactRedisList);
                    break;
                }
                if (containMobile(contactPojo.getMobile(), customerIndex)) {
                    deleteList.add(contactPojo);
                    continue;
                }
                // 判断客户联系人中电话是否存在
                if (containMobile(contactPojo.getMobile(), IndexTypeEnum.IDX_SAAS_CONTACT)) {
                    deleteList.add(contactPojo);
                    continue;
                }
                // 插入数据
                insertContact(contactFormEntity, customerEntityExt.getDataId(), data.getString(CustomerManagementEnum.NAME.getAttr()), contactPojo);
                deleteList.add(contactPojo);
            }

            deleteMap.put(customerCorpid, deleteList);
        }


        // 清空插入的数据
        userInfoStr = paasRedisHelper.getValue(ConfigConstant.SYNC_PRO_REDIS_PREFIX, ConfigConstant.ADD_CONTACT_TO_XBB);
        userInfoObj = JsonHelperUtil.parseObject(userInfoStr);

        JSONObject userInfo = new JSONObject();
        for (Map.Entry<String, Object> entry : userInfoObj.entrySet()) {
            String key = entry.getKey();
            List<SyncUserToContactPojo> list = JsonHelperUtil.parseArray(entry.getValue().toString(), SyncUserToContactPojo.class);
            if (deleteMap.containsKey(key)) {
                List<SyncUserToContactPojo> deleteList1 = deleteMap.get(key);
                // 取差集
                list = list.stream()
                        .filter(notPojo -> !deleteList1.stream().map(contactPojo -> contactPojo.getUserId()).collect(Collectors.toList()).contains(notPojo.getUserId()))
                        .collect(Collectors.toList());

            }
            JSONArray jsonArray = new JSONArray();
            jsonArray.addAll(list);
            userInfo.put(key, jsonArray);
        }
        // 缓存数据一天
        paasRedisHelper.setValue(ConfigConstant.SYNC_PRO_REDIS_PREFIX, ConfigConstant.ADD_CONTACT_TO_XBB, userInfo.toJSONString(), RedisTimeConstant.LONG_DURATION);
    }

    /***
     * 获取客户列表
     *
     * @param corpidSet 记录到销帮帮客户表单（formId：572924）字段text_28为corpid的数据
     * @throws
     * @return java.util.List<com.xbongbong.saas.domain.entity.ext.CustomerEntityExt
     * @author hongxiao
     * @date 2021-10-31 21:07
     * @since
     * @version
     */
    private List<CustomerEntityExt> getCustomerList (Set<String> corpidSet) {
        IndexTypeEnum customerIndex = indexTypeModel.getCustomerIndex(SYNC_CORPID_PRO, XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), SaasMarkEnum.SAAS.getCode());

        BoolQueryBuilder boolQueryBuilder = boolQuery();
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        boolQueryBuilder.filter(termQuery(StringConstant.CORPID + StringConstant.POINT + StringConstant.KEY_WORD, SYNC_CORPID_PRO));
        boolQueryBuilder.filter(termQuery("formId", SYNC_CUSTOMER_FORMID));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        boolQueryBuilder.filter(termsQuery("flowStatus", Arrays.asList(FlowStatusEnum.PASS.getType(), FlowStatusEnum.NOT_NEED_APPROVAL.getType())));

        boolQueryBuilder.filter(termsQuery("data." + CUSTOMER_FORM_CORPID + ".keyword", corpidSet));
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, customerIndex.getType()));
        sourceBuilder.query(boolQueryBuilder);
        //分页
        PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, 1000);
        SearchRequest searchRequest = new SearchRequest(customerIndex.getIndex());
        searchRequest.source(sourceBuilder);
        XbbAggregatedPage<CustomerEntityExt> esEntities;
        try {
            esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest,searchRequest, CustomerEntityExt.class);
        } catch (XbbException e) {
            esEntities = null;
        }
        if (Objects.isNull(esEntities)) {
            return null;
        }
        List<CustomerEntityExt> list = esEntities.getContent();
        return list;
    }

    /***
     * 插入联系人数据
     *
     * @param contactFormEntity 联系人表单
     * @param: customerId 客户数据id
     * @param: customerName　客户名称
     * @param: pojo　pojo中对应公司的员工
     * @throws
     * @return void
     * @author hongxiao
     * @date 2021-10-31 21:10
     * @since
     * @version
     */
    private void insertContact(PaasFormEntity contactFormEntity, Long customerId, String customerName, SyncUserToContactPojo pojo) {

        ContactEntityExt paasFormDataEntity = new ContactEntityExt();
        paasFormDataEntity.setCorpid(SYNC_CORPID_PRO);
        paasFormDataEntity.setSerialNo("");
        paasFormDataEntity.setOwnerId("");
        paasFormDataEntity.setCreatorId("");
        paasFormDataEntity.setDepartmentId(0L);
        paasFormDataEntity.setFlowStatus(FlowStatusEnum.NOT_NEED_APPROVAL.getType());
        paasFormDataEntity.setFormId(contactFormEntity.getId());
        paasFormDataEntity.setAppId(contactFormEntity.getAppId());
        paasFormDataEntity.setMenuId(contactFormEntity.getMenuId());
        paasFormDataEntity.setDel(DelEnum.NORMAL.getDel());
        JSONObject contactData = new JSONObject();
        //姓名
        contactData.put(ContactEnum.NAME.getAttr(), pojo.getUserName());
        // 电话
        List<JSONObject> phoneList = new ArrayList<>();
        JSONObject phone = new JSONObject();
        phone.put(StringConstant.PHONE_TYPE_ATTR, "1");
        phone.put(StringConstant.PHONE_TEL_ATTR, pojo.getMobile());
        phoneList.add(phone);
        contactData.put(ContactEnum.PHONE.getAttr(), phoneList);
        // 客户
        contactData.put(ContactEnum.CUSTOMER_NAME.getAttr(), customerId);
        // 客户名称　
        contactData.put(ContactEnum.CUSTOMER_NAME_LINK_TEXT.getAttr(), customerName);
        // 部门
        contactData.put(ContactEnum.DEPARTMENT.getAttr(), pojo.getDeptName());
        // 职务
        contactData.put(ContactEnum.POSITION.getAttr(), pojo.getRoleName());

        paasFormDataEntity.setData(contactData);
        paasFormDataEntity.setAddTime(DateTimeUtil.getInt());
        paasFormDataEntity.setUpdateTime(DateTimeUtil.getInt());
        try {
            contactModel.insert(paasFormDataEntity);
        } catch (XbbException e) {
            LOG.error("插入客户联系人失败！", e);
        }
    }

    /***
     * 查询联系人数量
     *
     * @param customerId　客户数据id
     * @throws
     * @return java.lang.Long
     * @author hongxiao
     * @date 2021-10-31 21:10
     * @since
     * @version
     */
    private Long getContactCount(Long customerId) {
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        boolQueryBuilder.filter(termQuery(StringConstant.CORPID + StringConstant.POINT + StringConstant.KEY_WORD, SYNC_CORPID_PRO));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        boolQueryBuilder.filter(termQuery("data." + ContactEnum.CUSTOMER_NAME.getAttr(), customerId));
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_CONTACT.getType()));
        sourceBuilder.query(boolQueryBuilder);
        SearchRequest searchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_CONTACT.getIndex());
        searchRequest.source(sourceBuilder);
        CountRequest countRequest = new CountRequest(searchRequest.indices()[0]);
        countRequest.query(searchRequest.source().query());
        Long count;
        try {
            count = xbbElasticsearchRestTemplate.count(countRequest);
        } catch (XbbException e) {
            count = 0L;
        }
        return count;
    }

    /***
     * 是否包含电话
     *
     * @param: mobile 电话
     * @throws
     * @return boolean
     * @author hongxiao
     * @date 2021-10-31 21:12
     * @since
     * @version
     */
    private boolean containMobile(String mobile, IndexTypeEnum indexTypeEnum) {
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        boolQueryBuilder.filter(termQuery(StringConstant.CORPID + StringConstant.POINT + StringConstant.KEY_WORD, SYNC_CORPID_PRO));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        boolQueryBuilder.filter(termQuery("data." + StringConstant.PHONE_ATTR + StringConstant.POINT + StringConstant.PHONE_TEL_ATTR + StringConstant.POINT + StringConstant.KEY_WORD, mobile));
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, indexTypeEnum.getType()));
        sourceBuilder.query(boolQueryBuilder);
        SearchRequest searchRequest = new SearchRequest(indexTypeEnum.getIndex());
        searchRequest.source(sourceBuilder);
        CountRequest countRequest = new CountRequest(searchRequest.indices()[0]);
        countRequest.query(searchRequest.source().query());
        Long count;
        try {
            count = xbbElasticsearchRestTemplate.count(countRequest);
        } catch (XbbException e) {
            count = 0L;
        }
        return count >= BasicConstant.ONE;
    }

}
